Skip to content

fix: extend TopicLinker for all messaging edge kinds (SENDS_TO, RECEIVES_FROM, PUBLISHES, LISTENS)#16

Merged
aksOps merged 7 commits into
mainfrom
feat/fulltext-search-index
Apr 3, 2026
Merged

fix: extend TopicLinker for all messaging edge kinds (SENDS_TO, RECEIVES_FROM, PUBLISHES, LISTENS)#16
aksOps merged 7 commits into
mainfrom
feat/fulltext-search-index

Conversation

@aksOps

@aksOps aksOps commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Fixes RAN-68: TopicLinker was ignoring SENDS_TO/RECEIVES_FROM/PUBLISHES/LISTENS edges, silently dropping cross-service CALLS edges for Tibco EMS, Azure Service Bus/Event Hub, and Spring Events patterns
  • Extends node kind matching to include EVENT and MESSAGE_QUEUE (alongside TOPIC/QUEUE)
  • Extends edge matching to treat SENDS_TO/PUBLISHES as producers and RECEIVES_FROM/LISTENS as consumers

Changes

  • TopicLinker.java: add three producer edge kinds (PRODUCES, SENDS_TO, PUBLISHES) and three consumer edge kinds (CONSUMES, RECEIVES_FROM, LISTENS) to the edge scan loop; add EVENT and MESSAGE_QUEUE to node kind filter
  • TopicLinkerTest.java: 4 new tests — SENDS_TO/RECEIVES_FROM linking, PUBLISHES/LISTENS via EVENT node, MESSAGE_QUEUE node kind, determinism test

Test plan

  • mvn test -Dtest=TopicLinkerTest passes (8 tests, 0 failures)
  • Full test suite passes
  • PE review and approval

🤖 Generated with Claude Code

aksOps and others added 7 commits April 1, 2026 16:11
…her query

Added GraphStore.findEndpointNeighborsBatch() that fetches all endpoint
neighbors for a list of node IDs in one MATCH ... WHERE n.id IN $nodeIds
query, eliminating up to 50 separate findNeighbors() calls per invocation.

QueryService.findRelatedEndpoints() now separates the direct-endpoint pass
from the neighbor pass, using the new batch method for the latter. Deduplication
and connected_via semantics are preserved.

Added 3 unit tests covering: batch usage (verifying findNeighbors is never
called), direct endpoint matches, and deduplication.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
…s for search

Store label_lower and fqn_lower on every node during bulkSave() so that
case-insensitive search can hit a B-tree index instead of doing a full
graph scan with toLower() on both sides of the CONTAINS predicate.

- nodeToProps(): adds label_lower/fqn_lower to the Neo4j property map
- bulkSave(): creates indexes on label_lower and fqn_lower
- EnrichCommand: creates label_lower/fqn_lower indexes alongside kind/layer/module/filePath
- GraphStore.search(text, limit): lowercase input, query against pre-lowered props
- GraphRepository.search(): same query update (SDN path)
- nodeFromNeo4j(): label_lower/fqn_lower implicitly excluded (no prop_ prefix)

All 1459 tests pass.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
…RE and ENDPOINT nodes

Implements RAN-61. GuardLinker uses file-path proximity (same file = match)
to infer that guards and middleware in a file protect endpoints in that file.
This surfaces security architecture in the graph for Spring @PreAuthorize,
@secured, DjangoAuth, FastAPIAuth, NestJSGuards, and generic middleware nodes.

- 9 unit tests: positive match, middleware, class-level, cross-file negative,
  no-guards, no-endpoints, duplicate avoidance, null filePath, determinism
- 1468 total tests pass, 0 failures

Co-Authored-By: Paperclip <noreply@paperclip.ing>
…tection

- Add GUARD, MIDDLEWARE, TOPIC, QUEUE, EVENT, MESSAGE_QUEUE to ENTRY_POINT_KINDS
  so they are never flagged as dead code (they are entry points / cross-cutting concerns)
- Remove invalid 'uses' edge kind from SEMANTIC_EDGE_KINDS (not a valid EdgeKind)
- Add 'protects' to SEMANTIC_EDGE_KINDS so PROTECTS edges from GuardLinker count
  as semantic usage when determining reachability
- Add two new tests: verifying new entry point kinds are excluded, and verifying
  'protects' is included / 'uses' is excluded from semantic edge kinds

Co-Authored-By: Paperclip <noreply@paperclip.ing>
- NestJSControllerDetector: bail out early if no @nestjs/ import to prevent false positives on Angular controllers and generic TypeScript
- NestJSGuardsDetector: bail out early if no @nestjs/ import to prevent false positives on any TypeScript with canActivate()
- NestJSControllerDetector: add edge.setTarget(node) on EXPOSES edges — previously missing, causing all class→endpoint edges to be silently dropped by GraphBuilder

Co-Authored-By: Paperclip <noreply@paperclip.ing>
…STENS edges

Tibco EMS, Azure Service Bus/Event Hub, and Spring Events emit different
edge kinds than Kafka/RabbitMQ. TopicLinker previously only matched
PRODUCES/CONSUMES, silently dropping cross-service CALLS edges for
all three messaging patterns.

- Add SENDS_TO and RECEIVES_FROM (Tibco/Azure) as producer/consumer edges
- Add PUBLISHES and LISTENS (Spring Events) as producer/consumer edges
- Add EVENT and MESSAGE_QUEUE node kinds to topic matching (alongside TOPIC/QUEUE)
- Add 4 new test cases: SENDS_TO/RECEIVES_FROM, PUBLISHES/LISTENS, MESSAGE_QUEUE, determinism

Co-Authored-By: Paperclip <noreply@paperclip.ing>
B-tree indexes on label_lower/fqn_lower cannot serve CONTAINS queries in
Neo4j — every search caused a full graph scan. Replace with a fulltext
index using the keyword analyzer so wildcard (*text*) queries are backed
by an index.

- Add FULLTEXT INDEX search_index on (n.label_lower, n.fqn_lower) in
  both GraphStore.bulkSave() and EnrichCommand secondary-index block
- Use keyword analyzer to preserve whole-property tokens (avoids Lucene
  tokenisation splitting FQNs on dots)
- Replace search() CONTAINS queries with
  db.index.fulltext.queryNodes() + *text* wildcard wrapping
- Escape Lucene special characters before wrapping in toLuceneQuery()
- Add CALL db.awaitIndexes(300) after secondary index creation in
  EnrichCommand so the first search request hits the index

Fixes RAN-66

Co-Authored-By: Paperclip <noreply@paperclip.ing>
@sonarqubecloud

sonarqubecloud Bot commented Apr 1, 2026

Copy link
Copy Markdown

@aksOps aksOps merged commit 4ca2662 into main Apr 3, 2026
10 checks passed
aksOps added a commit that referenced this pull request Apr 3, 2026
Resolves conflicts between backend chain (PRs #12-#16) and detection quality fixes:
- TopicLinker: preserved extended SENDS_TO/RECEIVES_FROM/PUBLISHES/LISTENS support from both chains
- GraphStore/EnrichCommand: kept search_index (fulltext, keyword analyzer, label_lower/fqn_lower) from backend chain
- QueryService: preserved batch endpoint neighbor query from backend chain + stats improvements
- NestJSControllerDetectorTest/NestJSGuardsDetectorTest: merged no-match discriminator tests

Co-Authored-By: Paperclip <noreply@paperclip.ing>
@aksOps aksOps deleted the feat/fulltext-search-index branch April 3, 2026 15:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant